import { inject, injectable, named } from "inversify";
import { DiagnosticSeverity, Uri } from "vscode";
import { IDocumentManager, IWorkspaceService } from "../../../common/application/types";
import { IConfigurationService, IDisposableRegistry, Resource } from "../../../common/types";
import { Diagnostics } from "../../../common/utils/localize";
import { SystemVariables } from "../../../common/variables/systemVariables";
import { EQPathSource } from "../../../debugger/extension/types";
import { IInterpreterHelper } from "../../../interpreter/contracts";
import { IServiceContainer } from "../../../ioc/types";
import { traceError } from "../../../logging";
import { BaseDiagnostic, BaseDiagnosticsService } from "../base";
import { IDiagnosticsCommandFactory } from "../commands/types";
import { DiagnosticCommandPromptHandlerServiceId, MessageCommandPrompt } from "../promptHandler";
import { DiagnosticCodes, DiagnosticScope, IDiagnostic, IDiagnosticHandlerService, IInvalidEQPathInDebuggerService } from "../types";

const messages = {
    [DiagnosticCodes.InvalidEQPathInDebuggerSettingsDiagnostic]: Diagnostics.invalidEQPathInDebuggerSettings,
    [DiagnosticCodes.InvalidEQPathInDebuggerLaunchDiagnostic]: Diagnostics.invalidEQPathInDebuggerLaunch,
};

class InvalidEQPathInDebuggerDiagnostic extends BaseDiagnostic {
    constructor(
        code:
            | DiagnosticCodes.InvalidEQPathInDebuggerLaunchDiagnostic
            | DiagnosticCodes.InvalidEQPathInDebuggerSettingsDiagnostic,
        resource: Resource,
    ) {
        super(code, messages[code], DiagnosticSeverity.Error, DiagnosticScope.WorkspaceFolder, resource, 'always');
    }
}

export const InvalidEQPathInDebuggerServiceId = 'InvalidEQPathInDebuggerServiceId';

@injectable()
export class InvalidEQPathInDebuggerService extends BaseDiagnosticsService
    implements IInvalidEQPathInDebuggerService {
    constructor(
        @inject(IServiceContainer) serviceContainer: IServiceContainer,
        @inject(IWorkspaceService) private readonly workspace: IWorkspaceService,
        @inject(IDiagnosticsCommandFactory) private readonly commandFactory: IDiagnosticsCommandFactory,
        @inject(IInterpreterHelper) private readonly interpreterHelper: IInterpreterHelper,
        @inject(IDocumentManager) private readonly documentManager: IDocumentManager,
        @inject(IConfigurationService) private readonly configService: IConfigurationService,
        @inject(IDisposableRegistry) disposableRegistry: IDisposableRegistry,
        @inject(IDiagnosticHandlerService)
        @named(DiagnosticCommandPromptHandlerServiceId)
        protected readonly messageService: IDiagnosticHandlerService<MessageCommandPrompt>,
    ) {
        super(
            [
                DiagnosticCodes.InvalidEQPathInDebuggerSettingsDiagnostic,
                DiagnosticCodes.InvalidEQPathInDebuggerLaunchDiagnostic,
            ],
            serviceContainer,
            disposableRegistry,
            true,
        );
    }
    public async diagnose(): Promise<IDiagnostic[]> {
        return [];
    }

    protected resolveVariables(eqPath: string, resource: Uri | undefined): string {
        const systemVariables = new SystemVariables(resource, undefined, this.workspace);
        return systemVariables.resolveAny(eqPath);
    }

    public async validateEQPath(
        eqPath?: string,
        eqPathSource?: EQPathSource,
        resource?: Uri,
    ): Promise<boolean> {
        eqPath = eqPath ? this.resolveVariables(eqPath, resource) : undefined;

        if (eqPath === '${command:eq.interpreterPath}' || !eqPath) {
            eqPath = this.configService.getSettings(resource).eqPath;
        }
        if (await this.interpreterHelper.getInterpreterInformation(eqPath).catch(() => undefined)) {
            return true;
        }
        traceError(`Invalid EQ Path '${eqPath}'`);
        if (eqPathSource === EQPathSource.launchJson) {
            this.handle([
                new InvalidEQPathInDebuggerDiagnostic(
                    DiagnosticCodes.InvalidEQPathInDebuggerLaunchDiagnostic,
                    resource,
                ),
            ])
                .catch((ex) => traceError('Failed to handle invalid eq path in launch.json debugger', ex))
                .ignoreErrors();
        } else {
            this.handle([
                new InvalidEQPathInDebuggerDiagnostic(
                    DiagnosticCodes.InvalidEQPathInDebuggerSettingsDiagnostic,
                    resource,
                ),
            ])
                .catch((ex) => traceError('Failed to handle invalid eq path in settings.json debugger', ex))
                .ignoreErrors();
        }
        return false;
    }
}


